home *** CD-ROM | disk | FTP | other *** search
/ Aminet 12 / Aminet 12 (1996)(GTI - Schatztruhe)[!][Jun 1996].iso / Aminet / dev / lang / Python13.lha / Python-1.3 / Lib / amigapath.py < prev    next >
Encoding:
Python Source  |  1996-04-02  |  7.1 KB  |  294 lines

  1. # Module 'amigapath' -- common operations on AMIGA pathnames
  2. # Irmen de Jong, april 1st, 1996 (no joke)
  3. # (adapted from `posixpath.py')
  4. #
  5. # 26-mar-96: fixed split, islink. Improved expanduser.
  6. # 1-apr-96: fixed expanduser (works 100% now)
  7. #
  8.  
  9. import amiga
  10. import stat
  11. import string
  12.  
  13. # Normalize the case of a pathname.  (string.lower)
  14. # On MS-DOS this may also turn slashes into backslashes; however, other
  15. # normalizations (such as optimizing '../' away) are not allowed
  16. # (another function should be defined to do that).
  17.  
  18. normcase = string.lower
  19.  
  20.  
  21. # Return wheter a path is absolute.
  22. # On the Amiga, this is when a ':' occurs in it.
  23.  
  24. def isabs(s):
  25.     return ':' in s
  26.  
  27.  
  28. # Join two pathnames.
  29. # Ignore the first part if the second part is absolute.
  30. # Insert a '/' unless the first part is empty or already ends in '/' or ':'.
  31.  
  32. def join(a, b):
  33.     if ':' in b: return b
  34.     if a == '' or a[-1:] == '/': return a + b
  35.     # Note: join('x', '') returns 'x/'; is this what we want?
  36.     if a[-1:]==':': return a+b
  37.     return a + '/' + b
  38.  
  39.  
  40. # Split a path in head (everything up to the last '/' or ':') and tail (the
  41. # rest).  If the path ends in '/' or ':', tail will be empty.  If there is no
  42. # '/' or ':' in the path, head  will be empty.
  43. # DIFFERENCE WITH posixpath: only ONE trailing '/' will be stripped from head!
  44. # (on the Amiga a double slash means "parent dir"! ) This means that if
  45. # head ends in a '/', you MUST add a '/' to it when reconstructing the path,
  46. # or you will lose the "parent dir" slash.
  47. # Functions that depend on this function are also affected!
  48. #  (basename, dirname)
  49. #
  50. # Changed since 13-dec-95. Suggested by Kent Polk, kent@eaenki.nde.swri.edu
  51.  
  52. def split(p):
  53.     i = string.rfind(p, '/')
  54.     j = string.rfind(p, ':')
  55.     if (i>j) and p[-1]=='/':
  56.         p=p[:-1]
  57.         i = string.rfind(p, '/')
  58.     if (j>i) or ((j>=0) and (i<0)): i=j
  59.     head, tail = p[:i+1], p[i+1:]
  60.     if head:
  61.         if head[-1]=='/': head=head[:-1]
  62.     return head, tail
  63.  
  64.  
  65. # Split a path in root and extension.
  66. # The extension is everything starting at the first dot in the last
  67. # pathname component; the root is everything before that.
  68. # It is always true that root + ext == p.
  69.  
  70. def splitext(p):
  71.     root, ext = '', ''
  72.     for c in p:
  73.         if c == '/':
  74.             root, ext = root + ext + c, ''
  75.         elif c == '.':
  76.             if ext:
  77.                 root, ext = root + ext, c
  78.             else:
  79.                 ext = c
  80.         elif ext:
  81.             ext = ext + c
  82.         else:
  83.             root = root + c
  84.     return root, ext
  85.  
  86.  
  87. # Split a pathname into a drive specification and the rest of the
  88. # path.  Useful on DOS/Windows/NT/Amiga; on Unix, the drive is always empty.
  89.  
  90. def splitdrive(p):
  91.     i = string.rfind(p,':') + 1
  92.     if i<=0: return '', p
  93.     return p[:i],p[i:]
  94.  
  95.  
  96. # Return the tail (basename) part of a path.
  97.  
  98. def basename(p):
  99.     return split(p)[1]
  100.  
  101.  
  102. # Return the head (dirname) part of a path.
  103.  
  104. def dirname(p):
  105.     return split(p)[0]
  106.  
  107.  
  108. # Return the longest prefix of all list elements.
  109.  
  110. def commonprefix(m):
  111.     if not m: return ''
  112.     prefix = m[0]
  113.     for item in m:
  114.         for i in range(len(prefix)):
  115.             if prefix[:i+1] <> item[:i+1]:
  116.                 prefix = prefix[:i]
  117.                 if i == 0: return ''
  118.                 break
  119.     return prefix
  120.  
  121.  
  122. # Is a path a symbolic link?
  123. # This will always return false on systems where amiga.lstat doesn't exist.
  124. # (or where S_ISLNK isn't defined)
  125. def islink(path):
  126.     try:
  127.         st = amiga.lstat(path)
  128.         return stat.S_ISLNK(st[stat.ST_MODE])
  129.     except (amiga.error, AttributeError):
  130.         return 0
  131.  
  132.  
  133. # Does a path exist?
  134. # This is false for dangling symbolic links.
  135.  
  136. def exists(path):
  137.     try:
  138.         st = amiga.stat(path)
  139.     except amiga.error:
  140.         return 0
  141.     return 1
  142.  
  143.  
  144. # Is a path an amiga directory?
  145. # This follows symbolic links, so both islink() and isdir() can be true
  146. # for the same path.
  147.  
  148. def isdir(path):
  149.     try:
  150.         st = amiga.stat(path)
  151.     except amiga.error:
  152.         return 0
  153.     return stat.S_ISDIR(st[stat.ST_MODE])
  154.  
  155.  
  156. # Is a path a regular file?
  157. # This follows symbolic links, so both islink() and isfile() can be true
  158. # for the same path.
  159.  
  160. def isfile(path):
  161.     try:
  162.         st = amiga.stat(path)
  163.     except amiga.error:
  164.         return 0
  165.     return stat.S_ISREG(st[stat.ST_MODE])
  166.  
  167.  
  168. # Are two filenames really pointing to the same file?
  169.  
  170. def samefile(f1, f2):
  171.     s1 = amiga.stat(f1)
  172.     s2 = amiga.stat(f2)
  173.     return samestat(s1, s2)
  174.  
  175.  
  176. # Are two open files really referencing the same file?
  177. # (Not necessarily the same file descriptor!)
  178.  
  179. def sameopenfile(fp1, fp2):
  180.     s1 = amiga.fstat(fp1)
  181.     s2 = amiga.fstat(fp2)
  182.     return samestat(s1, s2)
  183.  
  184.  
  185. # Are two stat buffers (obtained from stat, fstat or lstat)
  186. # describing the same file?
  187.  
  188. def samestat(s1, s2):
  189.     return s1[stat.ST_INO] == s2[stat.ST_INO] and \
  190.         s1[stat.ST_DEV] == s2[stat.ST_DEV]
  191.  
  192.  
  193. # Is a path a mount point?
  194. # (Does this work for all UNIXes?  Is it even guaranteed to work by POSIX?)
  195.  
  196. def ismount(path):
  197.     drive,rest = splitdrive(path)
  198.     if rest=='':
  199.         return 1
  200.     else:
  201.         return 0
  202.  
  203.  
  204. # Directory tree walk.
  205. # For each directory under top (including top itself, but excluding
  206. # '.' and '..'), func(arg, dirname, filenames) is called, where
  207. # dirname is the name of the directory and filenames is the list
  208. # files files (and subdirectories etc.) in the directory.
  209. # The func may modify the filenames list, to implement a filter,
  210. # or to impose a different order of visiting.
  211.  
  212. def walk(top, func, arg):
  213.     try:
  214.         names = amiga.listdir(top)
  215.     except amiga.error:
  216.         return
  217.     func(arg, top, names)
  218.     for name in names:
  219.         name = join(top, name)
  220.         if isdir(name) and not islink(name):
  221.             walk(name, func, arg)
  222.  
  223.  
  224. # Expand paths beginning with '~' or '~user'.
  225. # '~' means $HOME; '~user' means that user's home directory.
  226. # If the path doesn't begin with '~', or if the user or $HOME is unknown,
  227. # the path is returned unchanged (leaving error reporting to whatever
  228. # function is called with the expanded path as argument).
  229. # See also module 'glob' for expansion of *, ? and [...] in pathnames.
  230. # (A function should also be defined to do full *sh-style environment
  231. # variable expansion.)
  232.  
  233. def expanduser(path):
  234.     if path[:1] <> '~':
  235.         return path
  236.     i, n = 1, len(path)
  237.     while i < n and path[i] <> '/':
  238.         i = i+1
  239.     if i == 1:
  240.         if not amiga.environ.has_key('HOME'):
  241.             return path
  242.         userhome = amiga.environ['HOME']
  243.     else:
  244.         try:
  245.             import pwd
  246.             pwent = pwd.getpwnam(path[1:i])
  247.         except (KeyError,ImportError,SystemError):
  248.             return path            # ~user only works if pwd module works
  249.         userhome = pwent[5]
  250.     return userhome + path[i:]
  251.  
  252.  
  253. # Expand paths containing shell variable substitutions.
  254. # This expands the forms $variable and ${variable} only.
  255. # Non-existant variables are left unchanged.
  256.  
  257. _varprog = None
  258.  
  259. def expandvars(path):
  260.     global _varprog
  261.     if '$' not in path:
  262.         return path
  263.     if not _varprog:
  264.         import regex
  265.         _varprog = regex.compile('$\([a-zA-Z0-9_]+\|{[^}]*}\)')
  266.     i = 0
  267.     while 1:
  268.         i = _varprog.search(path, i)
  269.         if i < 0:
  270.             break
  271.         name = _varprog.group(1)
  272.         j = i + len(_varprog.group(0))
  273.         if name[:1] == '{' and name[-1:] == '}':
  274.             name = name[1:-1]
  275.         if amiga.environ.has_key(name):
  276.             tail = path[j:]
  277.             path = path[:i] + amiga.environ[name]
  278.             i = len(path)
  279.             path = path + tail
  280.         else:
  281.             i = j
  282.     return path
  283.  
  284.  
  285. # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
  286. # It should be understood that this may change the meaning of the path
  287. # if it contains symbolic links!
  288. # XXX: Currently not implemented on Amiga. Probably not useful anyway
  289. #      because x/y//z is different than x/y/z on the Amiga.
  290.  
  291. def normpath(path):
  292.     return path
  293.  
  294.